package com.cx.core.redis.aspect;

import com.cx.core.common.constant.ErrorEnum;
import com.cx.core.common.domin.BaseEntity;
import com.cx.core.common.exception.ServiceException;
import com.cx.core.redis.annotion.LimitAnnotation;
import com.cx.core.redis.annotion.LimitKey;
import com.cx.core.redis.annotion.LockAnnotation;
import com.cx.core.redis.service.LimitService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Order(1)
public class LimitAspect {

    private static final Logger log = LoggerFactory.getLogger(LimitAspect.class);
    @Autowired
    private LimitService limitService;

    @Around("@annotation(com.cx.core.redis.annotion.LimitAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LimitAnnotation lockAnnotation = method.getAnnotation(LimitAnnotation.class);
        String key = lockAnnotation.preKey();
        Object[] objects = joinPoint.getArgs();
        if (objects != null && objects.length != 0) {
            for (int i = 0; i < objects.length; i++) {
                Object object = objects[i];
                if (object instanceof BaseEntity) {
                    Field[] fields = object.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if (field.isAnnotationPresent(LimitKey.class)) {
                            LimitKey limitKey = field.getAnnotation(LimitKey.class);
                            if (limitKey != null) {
                                key = key + "_" + field.get(object).toString();
                            }
                        }
                    }
                }
            }
        }
        Boolean canVisit = limitService.limit(key, lockAnnotation.count(), lockAnnotation.time());
        if (canVisit) {
            return joinPoint.proceed();
        }
        throw new ServiceException(ErrorEnum.SYSTEM_BUSY);
    }
}